package di;


import ioc.*;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.*;

/**
 * Bean 的相关工具
 */
public class BeanUtils
{
    static DefaultBeanFactory defaultBeanFactory = new DefaultBeanFactory();

    public static Object[] getRealValues(List<Object> objs) throws Exception {
        if(objs==null || objs.size()<1)
        {
            return null;
        }
        Object[] result = new Object[objs.size()];
        for(int i=0;i<objs.size();i++)
        {
            //这里暂时只考虑对象是Bean引用的情况
            if(objs.get(i) instanceof BeanReference)
            {
                result[i] = defaultBeanFactory.getBean(((BeanReference) objs.get(i)).getBeanName());
            }else
                {
                    result[i] = objs.get(i);
                }
        }
        return result;
    }

    public static Constructor determineConstructor(IBeanDefinition bd,Object[] param) throws Exception {
        Constructor constructor = null;
        if(param==null)
        {
            return bd.getBeanClass().getConstructor(null);
        }
        constructor=bd.getConstructor();
        if(constructor!=null)
        {
            return constructor;
        }
        Class[] classes = new Class[param.length];
        int i=0;
        for(Object o : param)
        {
            classes[i++]=o.getClass();
        }
        try {
            constructor = bd.getBeanClass().getConstructor(classes);
        } catch (NoSuchMethodException e)
        {
            //这个异常无需处理
        }
        if(constructor == null )
        {
            Constructor[] constructors = bd.getBeanClass().getConstructors();
            outer :  for(Constructor c : constructors)
            {
                if(c.getParameterCount()==param.length)
                {
                    Class[] paras = c.getParameterTypes();
                    int z = 0;
                    for(Class p : paras)
                    {
                        if(!p.isAssignableFrom(classes[z++]))
                        {
                            continue outer;
                        }
                        //到这里代表找到了,可以断掉了
                        constructor =c;
                        break outer;
                    }
                }

            }
        }
        if(constructor!=null)
        {
            if(bd.isPrototype())
            {
                bd.setConstructor(constructor);
            }
            return constructor;
        }
        throw new RuntimeException("不存在对应的构造方法");
    }
    public static Method determineMethod(IBeanDefinition bd,Object[] param,Class type) throws NoSuchMethodException {
        if(type==null)
        {
            type = bd.getBeanClass();
        }
        Method method = null;
        String methodName= bd.getFactoryMethodName();
        if(param==null)
        {
            method=type.getMethod(methodName,null);
        }
        if(method!=null)
        {
            return method;
        }
        Class[] classes = new Class[param.length];
        int i=0;
        for(Object o : param)
        {
            classes[i++]=o.getClass();
        }
        try {
            method = type.getMethod(methodName,classes);
        } catch (NoSuchMethodException e)
        {
            //这个异常无需处理
        }
        if(method == null )
        {
            Method[] methods = type.getMethods();
            outer :  for(Method m : methods)
            {
                if(m.getParameterCount()==param.length)
                {
                    Class[] paras = m.getParameterTypes();
                    int z = 0;
                    for(Class p : paras)
                    {
                        if(!p.isAssignableFrom(classes[z++]))
                        {
                            continue outer;
                        }
                        //到这里代表找到了,可以断掉了
                        method =m;
                        break outer;
                    }
                }

            }
        }
        if(method!=null)
        {
            if(bd.isPrototype())
            {
                bd.setFactoryMethod(method);
            }
            return method;
        }
        throw new RuntimeException("不存在对应的工厂方法");
    }

    /**
     * 获取所有方法包括父类的
     */
    public static Set<Method> getAllMethod(Class cls)
    {
        Set<Method> methods = new LinkedHashSet<>();
        while(cls!=null)
        {
            Class[] currentInterface = cls.getInterfaces();

            for(Class interfaceClass : currentInterface)
            {
                while(interfaceClass!=null)
                {
                    methods.addAll(Arrays.asList(interfaceClass.getDeclaredMethods()));
                    interfaceClass = interfaceClass.getSuperclass();
                }
            }
            methods.addAll(Arrays.asList(cls.getDeclaredMethods()));
            cls=cls.getSuperclass();
        }
        return methods;
    }

}
